export const MATRIX_SIZE = 10;
const BASE_PROBABILITY = 20; // 100 / 5
const COLOR_COUNT = 5;
export const COLORS = [cc.Color.RED, cc.Color.GREEN, cc.Color.BLUE, cc.Color.ORANGE, cc.Color.MAGENTA];


export default class Q1Util {

    adjustX: number = 0; // 左边和上方元素不同色时的概率调整值
    adjustY: number = 0; // 左边和上方元素同色时的概率调整值

    // 初始化调整值
    setAdjust(adjustX: number, adjustY: number) {
        this.adjustX = adjustX;
        this.adjustY = adjustY;
    }

    // 生成一个min-max之间的随机数
    random(min: number, max: number): number {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    // 根据概率数组、生成的随机数，返回随机数所对应的概率数组的索引
    randomIndex(probability: number[]): number {
        let total = probability.reduce((acc, cur) => acc + cur, 0);
        let random = this.random(0, total - 1);
        let sum = 0;
        for (let i = 0; i < probability.length; i++) {
          sum += probability[i];
          if (random < sum) {
            return i;
          }
        }

        return probability.length - 1;
    }

    // 根据左边、上边两个点的颜色，生成当前点的颜色概率数组，规则如下：
    // (m, n - 1)所属颜⾊的概率增加 X% 
	// (m - 1, n)所属颜⾊的概率增加 X% 
	// 若(m, n - 1)和(m - 1 ,n)同⾊，则该颜⾊的概率只增加 Y% 
	// 其他颜⾊平分剩下的概率
    genColorProbability(probabilityMap: Map<string, number[]>, leftIdx: number, upIdx: number): number[] {
        let key: string = '';
        if (leftIdx < upIdx) {
            key = `${leftIdx}-${upIdx}`;
        } else {
            key = `${upIdx}-${leftIdx}`;
        }

        // 已经存在了
        if (probabilityMap.has(key)) {
            return probabilityMap.get(key);
        }

        let colorsProbability: number[] = [0, 0, 0, 0, 0];
        let remainProbability: number = BASE_PROBABILITY * COLOR_COUNT;
        let remainColorCnt = COLOR_COUNT;

        if (leftIdx === upIdx && leftIdx !== -1) { // 左和上同色
            colorsProbability[leftIdx] = BASE_PROBABILITY + this.adjustY;
            remainProbability -= colorsProbability[leftIdx];
            remainColorCnt--;
        } else {
            if (leftIdx !== -1) {
                colorsProbability[leftIdx] = BASE_PROBABILITY + this.adjustX;
                remainProbability -= colorsProbability[leftIdx];
                remainColorCnt--;
            }
            if (upIdx !== -1) {
                colorsProbability[upIdx] = BASE_PROBABILITY + this.adjustX;
                remainProbability -= colorsProbability[upIdx];
                remainColorCnt--;
            }
        }

        if (remainProbability < 0) {
            remainProbability = 0;
        }

        let avgProbability = Math.floor(remainProbability / remainColorCnt);
        let setCnt = 0;
        for (let i = 0; i < COLOR_COUNT; i++) {
            if (colorsProbability[i] === 0) {
                setCnt++;
                if (setCnt == remainColorCnt ) { // 有可能无法平分，最后一个用剩余的
                    colorsProbability[i] = remainProbability;
                    break;
                } else {
                    colorsProbability[i] = avgProbability;
                    remainProbability -= avgProbability;
                }
            }
        }

        // 缓存计算过的概率数组
        probabilityMap.set(key, colorsProbability);

        return colorsProbability;
    }

    // 产生一个元素的颜色
    // 首先根据左边、上边两个点的颜色，生成当前点的颜色概率数组，再根据概率数组随机选取颜色
    generateColor(matrix: number[][], probabilityMap: Map<string, number[]>, m: number, n: number): number {
        let leftIdx: number = -1;
        let upIdx: number = -1;
        if (m >= 1) {
            leftIdx = matrix[m - 1][n];
        }
        if (n >= 1) {
            upIdx = matrix[m][n - 1];
        }

        let colorsProbability: number[] = this.genColorProbability(probabilityMap, leftIdx, upIdx);

        let colorIdx: number = this.randomIndex(colorsProbability);

        return colorIdx;
    }

    // 生成一个二维矩阵,矩阵的下标(m, n)表示从左到右、从上到下的第m行第n列
    // 矩阵的每个元素表示该位置的颜色索引
    generateColorIdxs(): number[][] {
        let matrix: number[][] = [];
        let probabilityMap: Map<string, number[]> = new Map();

        for (let  m= 0; m < MATRIX_SIZE; m++) {
            matrix[m] = [];
            for (let n = 0; n < MATRIX_SIZE; n++) {
                if ((m === 0 && n === 0) ||
                    (this.adjustX === 0 && this.adjustY === 0)) {
                    // 左上角元素和不需要调整的情况，随机选取颜色
                    matrix[m][n] = this.random(0, COLOR_COUNT - 1);
                } else {
                    // 根据规则生成其他点的颜色
                    matrix[m][n] = this.generateColor(matrix, probabilityMap, m, n);
                }
            }
        }

        probabilityMap.clear();

        return matrix;
    }
}
